<?php


namespace models\Business\Tbk;


use models\Business\Member;
use models\DAO\MemberModel;
use models\Exception\Business\MemberException;
use models\Exception\Business\TbkorderException;
use models\Exception\DAO\ModelDriverException;
use models\Exception\DAO\ModelException;
use models\Exception\DAO\ModelReflectionException;
use models\Exception\DAO\ModelSqlException;
use models\Exception\Service\ServiceException;
use models\Exception\Transformer\TransformerException;
use models\Service\MemberService;
use models\Service\SystemService;
use models\Service\TbkorderService;
use models\Service\TurnoverService;
use Yaf\Registry;

class TbkOrder
{
    /**
     * 用户晒单
     * @param string $order_sn
     * @param int $member_id
     * @return array|mixed|null
     * @throws MemberException
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws ServiceException
     * @throws TbkorderException
     * @throws TransformerException
     */
    static public function rebate($order_sn = '', $member_id = 0) {
        // 查询订单接口
        try {
            if (empty($order_sn))
                throw new TbkorderException(TbkorderException::TBKORDER_ID_IS_EMPTY, TbkorderException::TBKORDER_ID_IS_EMPTY_NO);

            if (empty($member_id))
                throw new MemberException(MemberException::MEMBER_ID_IS_EMPTY, MemberException::MEMBER_ID_IS_EMPTY_NO);

            $rebate_order_is_exists = TbkorderService::getInstance()->getOne($order_sn);
            if ($rebate_order_is_exists) {
                if ($rebate_order_is_exists['member_id'] != 0 && $rebate_order_is_exists['member_id'] != $member_id)
                    throw new TbkorderException(TbkorderException::TBKORDER_DENIED, TbkorderException::TBKORDER_DENIED_NO);

                $update_arr['member_id'] = $member_id;
                if ($rebate_order_is_exists['order_stats'] == 4 || $rebate_order_is_exists['order_stats'] == 3 || $rebate_order_is_exists['order_stats'] == 2) {
                    $system = SystemService::getInstance()->getOne(1);

                    $rebate_rate = isset($system['tbk_rebate_rate']) ? sprintf('%.2f', $system['tbk_rebate_rate']) : 0;
                    $parent_rebate_rate = isset($system['tbk_parent_rate']) ? sprintf('%2.f', $system['tbk_parent_rate']): 0;
                    $grand_parent_rebate_rate = isset($system['tbk_sub_rate']) ? sprintf('%.2f', $system['tbk_sub_rate']) : 0;

                    $update_arr['rebate'] = $rebate_order_is_exists['commission'] != '0.00' ?
                        sprintf('%.2f', $rebate_order_is_exists['commission'] * $rebate_rate / 100) :
                        sprintf('%.2f', $rebate_order_is_exists['settlement_amount'] * $rebate_order_is_exists['commission_ratio'] / 100  * $rebate_rate / 100);
                    $update_arr['parent_rebate'] = $rebate_order_is_exists['commission'] != '0.00' ?
                        sprintf('%.2f', $rebate_order_is_exists['commission'] * $parent_rebate_rate / 100) :
                        sprintf('%.2f', $rebate_order_is_exists['settlement_amount'] * $rebate_order_is_exists['commission_ratio'] / 100  * $parent_rebate_rate / 100);
                    $update_arr['grand_parent_rebate'] = $rebate_order_is_exists['commission'] != '0.00' ?
                        sprintf('%.2f', $rebate_order_is_exists['commission'] * $grand_parent_rebate_rate / 100) :
                        sprintf('%.2f', $rebate_order_is_exists['settlement_amount'] * $rebate_order_is_exists['commission_ratio'] / 100  * $grand_parent_rebate_rate / 100);
                    if ($rebate_order_is_exists['order_stats'] == 4)
                        $update_arr['order_stats'] = 5;

                    $member = Member::getAllParentByMemberId($member_id);
                    // 按照lvl排序，并只读取三级
                    array_multisort(array_column($member, 'lvl'), SORT_ASC, $member);

                    $update_balance_arr = $insert_turnover_arr = [];
                    foreach ($member as $idx => $member_info) {
                        $now = date('Y-m-d H:i:s', time());
                        if ($idx <= 2) {
                            $balance = $idx == 0 ? $update_arr['rebate'] : ($idx == 1 ? $update_arr['parent_rebate'] : ($idx == 2 ? $update_arr['grand_parent_rebate'] : 0));
                            if ($rebate_order_is_exists['order_stats'] == 4) {
                                array_push($update_balance_arr, [
                                    'id' => $member_info['id'],
                                    'balance' => $member_info['balance'] + $balance
                                ]);

                                array_push($insert_turnover_arr, ['member_id' => $member_info['id'], 'type' => 6,
                                    'currency' => $member_info['balance'], 'amount' => $balance,
                                    'remain' => sprintf('%.2f', $member_info['balance'] + $balance), 'stats' => 1,
                                    'remark' => $idx == 0 ? '自购返利' : ($idx == 1 ? '好友购物返利' : ($idx == 2 ? '间属好友购物返利' : '')),
                                    'created_at' => $now]);
                            }
                        }
                    }

                    TbkorderService::getInstance()->update($update_arr, $order_sn);
                    Registry::get('tbk_log')->info('需要淘客订单数据: ' . json_encode($update_arr));

                    if (!empty($update_balance_arr)) {
                        Registry::get('tbk_log')->info('需要修改的余额数据: ' . json_encode($update_balance_arr));
                        MemberService::getInstance()->batchUpdate($update_balance_arr);
                    }

                    if (!empty($insert_turnover_arr)) {
                        Registry::get('tbk_log')->info('需要新增的流水数据: ' . json_encode($insert_turnover_arr));
                        TurnoverService::getInstance()->batchInsert($insert_turnover_arr);
                    }

                }

                if (empty($update_arr))
                    $rebate_order = $rebate_order_is_exists;
                else
                    $rebate_order = TbkorderService::getInstance()->update($update_arr, $order_sn);
            } else {
                $rebate_order = TbkorderService::getInstance()->create($order_sn, $member_id);
            }

            return $rebate_order;

        } catch (TbkorderException $e) {
            throw $e;
        } catch (MemberException $e) {
            throw $e;
        }  catch (ModelDriverException $e) {
            if ($e->getCode() == ModelDriverException::DRIVER_EXCEPTION_MSG_NO)
                throw new TbkorderException(TbkorderException::TBKORDER_CREATE_FAILURE, TbkorderException::TBKORDER_CREATE_FAILURE_NO);
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

    /**
     * 批量修改tbk晒单
     * @param $order_array
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws ServiceException
     * @throws TransformerException
     */
    static public function collectTbkOrder($order_array) {
        try {
            $order_sn_arr = array_column($order_array, 'order_sn');
            $order_is_exists = [];
            if (!empty($order_sn_arr)) {
                $order_is_exists = TbkorderService::getInstance()->getList(1, count($order_sn_arr), 'desc', 'created_at',
                    ['groupOp' => 'AND', 'rules' => [
                        ['field' => 'order_sn', 'op' => 'in', 'data' => implode(', ', $order_sn_arr)]]]);

            }

            $insert_data_arr = $update_data_arr = [];
            if (!empty($order_is_exists['data'])) {
                $exists_product_id_arr = array_column($order_is_exists['data'], 'order_sn');

                foreach ($order_array as $idx => $order_info) {
                    // 已存在的商品写入更新数据
                    if (in_array($order_info['order_sn'], $exists_product_id_arr)) {
                        array_push($update_data_arr, $order_info);
                    } // 不存在的商品写入插入数组
                    else {
                        array_push($insert_data_arr, $order_info);
                    }
                }
            } else
                $insert_data_arr = $order_array;


            if (!empty($update_data_arr)) {
                // 更新数组长度大于1，批量插入
                if (count($update_data_arr) > 1)
                    TbkorderService::getInstance()->batchUpdate($update_data_arr);
                // 更新数组长度等于1，单条更新
                else {
                    $update_arr = array_values($update_data_arr);
                    $update_arr = $update_arr[0];
                    $order_sn = $update_arr['order_sn'];
                    TbkorderService::getInstance()->update($update_arr, $order_sn);
                }
            }

            // 插入数据存在
            if (!empty($insert_data_arr))
                // 批量插入
                TbkorderService::getInstance()->batchInsert($insert_data_arr);
        } catch (ModelDriverException $e) {
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

    /**
     * 批量导入tbk订单
     * @param string $order_sn
     * @return array|mixed|null
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws TbkorderException
     * @throws TransformerException
     * @throws \models\Exception\Service\ServiceException
     */
    static public function importRebate($order_sn = '') {
        if (empty($order_sn))
            throw new TbkorderException(TbkorderException::TBKORDER_ID_IS_EMPTY, TbkorderException::TBKORDER_ID_IS_EMPTY_NO);

        $update_balance_arr = $insert_turnover_arr = [];
        try {
            // $item_id = "", $title = "", $aliwangwang = "", $shop_title = "", $total = 0,
            // $price = 0.00, $category = "", $order_sn = "", $sub_order_sn = "", $order_stats = 0, $type = "",
            // $payment_amount = 0.00, $settlement_amount = 0.00, $commission_ratio = 0.00, $commission = 0.00,
            // $subsidy_ratio = 0.00, $subsidy_amount = 0.00, $subsidy_type = "", $income_ratio = 0.00,
            // $split_ratio = 0.00, $income = 0.00, $tech_service_rate = 0.00, $tech_service_fee = 0.00,
            // $effect_estimates = 0.00, $estimated_income = 0.00, $source_id = 0, $source_name = "",
            // $ad_id = 0, $ad_name = "", $transaction_platform = "", $member_id = 0
            $tbk_order_info = TbkorderService::getInstance()->create('', '', '','', '', 0,
                0.00, 0, $order_sn, $order_sn, 0, '', 0.00, 0.00,
                0.00, 0.00, 0.00, 0.00, 0.00, 0.00,
                0.00, 0.00, 0.00, 0.00, 0.00, 0.00,
                0, '', 0, '', '', Registry::get('jwt_info')->id
            );
        } catch (ModelDriverException $e) {
            // 数据插入失败 读取数据库
            $tbk_order_info = TbkorderService::getInstance()->getOne(['groupOp' => 'AND', 'rules' => [
//                ['field' => 'member_id', 'op' => 'eq', 'data' => Registry::get('jwt_info')->id],
                ['field' => 'order_sn', 'op' => 'eq', 'data' => $order_sn]]]);
        } finally {
            if ($tbk_order_info['member_id'] != 0 && $tbk_order_info['member_id'] != Registry::get('jwt_info')->id)
                throw new TbkorderException(TbkorderException::TBKORDER_DENIED, TbkorderException::TBKORDER_DENIED_NO);

            // 订单状态(1为订单失败,2为订单付款,3为订单成功,4为订单结算,5为已经为会员结算过余额了,默认0)
            // 订单状态为4，开始计算
            if ($tbk_order_info['order_stats'] == 4) {
                // 给会员和他的上级、上上级增加余额
                $system = SystemService::getInstance()->getOne(1);
                $real_commission = $tbk_order_info['commission'] - $tbk_order_info['tech_service_fee'];

                // 系统表中 晒单用户的上级用户的返利比例无不为0时，计算其返利金额
                $info = Member::getAllParentByMemberId(Registry::get('jwt_info')->id);
                // 按照lvl排序，并只读取三级
                array_multisort(array_column($info, 'lvl'), SORT_ASC, $info);

                foreach ($info as $idx => $member_info) {
                    $now = date('Y-m-d H:i:s', time());
                    if ($idx <= 2) {
                        $rate = $idx == 0 ? $system['tbk_rebate_rate'] :
                            ($idx == 1 ? $system['tbk_parent_rate'] :
                                ($idx == 2 ? $system['tbk_sub_rate'] : 0));
                        // 晒单会员 晒单会员上级会员 晒单会员上上级会员 的返利比例不为0时 为指定会员增加余额并新增流水记录
                        if ($rate != 0) {
                            $balance = sprintf('%.2f', round($real_commission * $rate / 100, 2));
                            array_push($update_balance_arr, ['member_id' => $member_info['id'],
                                'balance' => '`balance` + ' . $balance]);

                            array_push($insert_turnover_arr, ['member_id' => $member_info['id'], 'type' => 6,
                                'currency' => $member_info['balance'], 'amount' => $balance,
                                'remain' => round(($member_info['balance'] + $balance), 2), 'stats' => 1,
                                'remark' => $idx == 0 ? '自购返利' : ($idx == 1 ? '好友购物返利' : ($idx == 2 ? '间属好友购物返利' : '余额增加')),
                                'created_at' => $now]);
                        }
                    }
                }
            }
            // 非结算状态 直接返回订单信息
            else
                return $tbk_order_info;
        }

        if (empty($update_balance_arr) || empty($insert_turnover_arr))
            throw new TbkorderException(TbkorderException::TBKORDER_REBATE_INVALID, TbkorderException::TBKORDER_REBATE_INVALID_NO);

        $conn = MemberModel::getInstance()->getConn();
        $conn->beginTransaction();
        try {
            // 修改余额
            if (!empty($update_balance_arr)) {
                foreach ($update_balance_arr as $row) {
                    $sql = "UPDATE `member` SET `balance` = " . $row['balance'] . " WHERE `id` = '" . $row['member_id'] . "';";
                    Registry::get('tbk_log')->info("用户自购返利sql: " . $sql);
                    $conn->executeQuery($sql);
                }
            }


            // 修改turnover记录
            if (!empty($insert_turnover_arr)) {
                $sql = "INSERT INTO `turnover` (`" . implode("`, `", array_keys($insert_turnover_arr[0])) . "`) VALUES ";
                foreach ($insert_turnover_arr as $row) {
                    $sql .= "('" . implode("', '", array_values($row)). "'),";
                }
                $sql = substr($sql, 0, strrpos($sql, ',')) . ';';
                Registry::get('tbk_log')->info("用户晒单流水sql: " . $sql);
                $conn->executeQuery($sql);
            }

            if ($tbk_order_info['member_id'] == 0) {
                "UPDATE `tbkorder` SET `order_stats` = 5, `member_id` = " . Registry::get('jwt_info')->id . " WHERE `id` = " . $tbk_order_info['id'];
                $tbk_order_info['member_id'] = Registry::get('jwt_info')->id;
            } else
                $sql = "UPDATE `tbkorder` SET `order_stats` = 5 WHERE `id` = " . $tbk_order_info['id'];
            Registry::get('tbk_log')->info("修改晒单记录状态为已为会员返回余额: " . $sql);
            $conn->executeQuery($sql);

            $conn->commit();

            return $tbk_order_info;
        } catch (\Exception $e) {
            $conn->rollBack();
            Registry::get('tbk_log')->err("用户晒单sql错误: " . $e->getMessage());
        }

    }

    /**
     * 获取晒单列表
     * @param array $parameters
     * @return array|mixed
     * @throws ModelDriverException
     * @throws ModelException
     * @throws ModelReflectionException
     * @throws ModelSqlException
     * @throws ServiceException
     * @throws TbkorderException
     * @throws TransformerException
     */
    static public function getOrderList($parameters = []) {
        try {
            $from_api = false;
            $rules = $condition = [];
            if (isset($parameters['from_api']) && $parameters['from_api'] === true)
                $from_api = true;


            if (isset($parameters['stats'])) {
                if ($from_api === true && $parameters['stats'] == 0) {
                    array_push($rules, ['field' => 'order_stats', 'op' => 'in', 'data' => '0,1,2,3,4,5']);
                } else if ($from_api === true && $parameters['stats'] == 4) {
                    array_push($rules, ['field' => 'order_stats', 'op' => 'eq', 'data' => 0]);
                } else if ($from_api === true && $parameters['stats'] == 3) {
                    array_push($rules, ['field' => 'order_stats', 'op' => 'eq', 'data' => 5]);
                } else {
                    array_push($rules, ['field' => 'order_stats', 'op' => 'eq', 'data' => $parameters['stats']]);
                }
            }
            if (isset($parameters['order_stats']))
                array_push($rules, ['field' => 'order_stats', 'op' => 'eq', 'data' => $parameters['order_stats']]);

            if (isset($parameters['sn']))
                array_push($rules, ['field' => 'order_sn', 'op' => 'eq', 'data' => $parameters['sn']]);

            if (isset($parameters['mobile']) && $from_api === false) {
                $member = Member::getMemberList(['mobile' => $parameters['mobile']]);
                if (empty($member['data']))
                    throw new MemberException(MemberException::MEMBER_IS_NOT_EXISTS, MemberException::MEMBER_IS_NOT_EXISTS_NO);
                if (count($member['data']) > 1)
                    array_push($rules, ['field' => 'member_id', 'op' => 'in', 'data' => implode(',', array_column($member['data'], 'id'))]);
                else if (count($member['data']) == 1)
                    array_push($rules, ['field' => 'member_id', 'op' => 'eq', 'data' => implode('', array_column($member['data'], 'id'))]);
            }

            if (isset($parameters['start_payment_at']))
                array_push($rules, ['field' => 'pay_time', 'op' => 'ge', 'data' => date("Y-m-d 00:00:00", strtotime(str_replace('/', '-', $parameters['start_payment_at'])))]);

            if (isset($parameters['end_payment_at']))
                array_push($rules, ['field' => 'pay_time', 'op' => 'le', 'data' => date("Y-m-d 23:59:59", strtotime(str_replace('/', '-', $parameters['end_payment_at'])))]);

            if (isset($parameters['start_settlement_at']))
                array_push($rules, ['field' => 'settlement_time', 'op' => 'ge', 'data' => date("Y-m-d 00:00:00", strtotime(str_replace('/', '-', $parameters['start_settlement_at'])))]);

            if (isset($parameters['end_settlement_at']))
                array_push($rules, ['field' => 'settlement_time', 'op' => 'le', 'data' => date("Y-m-d 23:59:59", strtotime(str_replace('/', '-', $parameters['end_settlement_at'])))]);

            $son = $grand_son = [];
            // 前端获取指定用户的好友淘宝晒单列表
            if ($from_api === true && isset($parameters['friend']) && $parameters['friend'] == 1) {
                $friend_list = Member::getAllFriendByMemberId(Registry::get('jwt_info')->id);
                $member_id_arr = array_values(array_diff(array_keys($friend_list), [Registry::get('jwt_info')->id]));
                if (!empty($member_id_arr))
                    array_push($rules, ['field' => 'member_id', 'op' => 'in', 'data' => implode(',', $member_id_arr)]);
                else
                    throw new MemberException("暂时没有好友，赶紧去推荐好友", 404);
                foreach ($friend_list as $member_id => $parent_id) {
                    if ($parent_id == Registry::get('jwt_info')->id) {
                        array_push($son, $member_id);
                    } else
                        array_push($grand_son, $member_id);
                }
            } else if ($from_api === true && (!isset($parameters['friend']) || $parameters['friend'] != 1))
                array_push($rules, ['field' => 'member_id', 'op' => 'eq', 'data' => Registry::get('jwt_info')->id]);


            if (!empty($rules))
                $condition = ['groupOp' => 'AND', 'rules' => $rules];

            $order_list = TbkorderService::getInstance()->getList(
                isset($parameters['page']) ? $parameters['page'] : 1,
                isset($parameters['page_size']) ? $parameters['page_size'] : 10,
                isset($parameters['sort']) ? $parameters['sort'] : 'desc',
                isset($parameters['order']) ? $parameters['order'] : 'order_sn',
                $condition
            );

            if (empty($order_list['data']))
                throw new TbkorderException(TbkorderException::TBKORDER_IS_NOT_EXISTS, TbkorderException::TBKORDER_IS_NOT_EXISTS_NO);

            if ($from_api === true && (!empty($grand_son) || !empty($son))) {
                $system = SystemService::getInstance()->getOne(1);
                foreach ($order_list['data'] as $idx => $order_info) {
                    $order_list['data'][$idx]['image'] = strpos($order_info['image'], 'http') === false ? 'https:' . $order_info['image'] : $order_info['image'];
                    $order_list['data'][$idx]['stats_name'] = $order_info['order_stats'] == 1 ? '已失效' :
                        ($order_info['order_stats'] == 4 ? '已结算' : (in_array($order_info['order_stats'], [2, 3]) ? '已付款' :
                            ($order_info['order_stats'] == 5 ? '已返还' : '未知状态')));
                    if ($order_info['order_stats'] == 4) {
                        if (in_array($order_info['member_id'], $son))
                            $order_list['data'][$idx]['rebate'] = ($order_info['commission'] - $order_info['tech_service_fee']) * $system['tbk_parent_rate'] / 100;
                        else if (in_array($order_info['member_id'], $grand_son))
                            $order_list['data'][$idx]['rebate'] = ($order_info['commission'] - $order_info['tech_service_fee']) * $system['tbk_sub_rate'] / 100;
                        else if ($order_info['member_id'] == Registry::get('jwt_info')->id)
                            $order_list['data'][$idx]['rebate'] = ($order_info['commission'] - $order_info['tech_service_fee']) * $system['tbk_parent_rate'] / 100;
                        else
                            $order_list['data'][$idx]['rebate'] = 0;
                    }
                }
            } else {
                $order_list = Member::getMembersByModules($order_list);
                foreach ($order_list['data'] as $idx => $order_info) {
                    $order_list['data'][$idx]['image'] = strpos($order_info['image'], 'http') === false ? 'https:' . $order_info['image'] : $order_info['image'];
                    $order_list['data'][$idx]['stats_name'] = $order_info['order_stats'] == 1 ? '已失效' :
                        ($order_info['order_stats'] == 4 ? '已结算' : (in_array($order_info['order_stats'], [2, 3]) ? '已付款' :
                            ($order_info['order_stats'] == 5 ? '已返还' : '未知状态')));
                }
            }

            return $order_list;
        } catch (ModelDriverException $e) {
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

    static public function getOrderBySn($sn = '') {
        try {
            return TbkorderService::getInstance()->getOne(['groupOp' => 'AND', 'rules' => [
                ['field' => 'order_sn', 'op' => 'eq', 'data' => $sn]]]);
        } catch (ModelDriverException $e) {
            throw $e;
        } catch (ModelException $e) {
            throw $e;
        } catch (ModelReflectionException $e) {
            throw $e;
        } catch (ModelSqlException $e) {
            throw $e;
        } catch (ServiceException $e) {
            throw $e;
        } catch (TransformerException $e) {
            throw $e;
        }
    }

}
